﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web;
using System.Threading;
using System.Diagnostics;

namespace Carbon.Web.Forms
{
    public class DisposeHttpModule : IHttpModule
    {
        private static readonly String Prefix;
        private static readonly String DisposeList;
        private static readonly String DisposeModuleEnabled;

        static DisposeHttpModule()
        {
            Prefix = typeof(DisposeHttpModule).FullName + ".";
            DisposeList = Prefix + "ToDispose";
            DisposeModuleEnabled = Prefix + "Enabled";
        }

        #region IHttpModule Members

        public void Dispose()
        {
            
        }

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(context_BeginRequest);
            context.EndRequest += new EventHandler(context_EndRequest);
        }

        private void context_EndRequest(object sender, EventArgs e)
        {
            HttpContext current = HttpContext.Current;

            List<IDisposable> disposables = null;

            disposables = (List<IDisposable>)current.Items[DisposeList];

            if (disposables == null)
                return;

            foreach (IDisposable disposable in disposables)
            {
                try
                {
                    disposable.Dispose();
                }
                catch (Exception ex)
                {
                    try
                    {
                        Log.Error(ex);
                    }
                    catch
                    {
                    }
                }
            }
        }

        public static T GetThreadObject<T>() where T : class
        {
            HttpContext current = HttpContext.Current;

            EnsureEnabled();

            return (T)current.Items[typeof(T).FullName];
        }

        public static T GetThreadObject<T>(String name) where T : class
        {
            HttpContext current = HttpContext.Current;

            EnsureEnabled();

            return (T)current.Items[Prefix + name];
        }

        public static void SetThreadObject<T>(String name, T value) where T : class
        {
            HttpContext current = HttpContext.Current;

            EnsureEnabled();

            current.Items[Prefix + name] = value;

            if (value is IDisposable)
            {
                AddDisposable((IDisposable)value);
            }
        }

        public static void SetThreadObject<T>(T value) where T : class
        {
            HttpContext current = HttpContext.Current;

            EnsureEnabled();

            current.Items[typeof(T).FullName] = value;
        }

        private static void EnsureEnabled()
        {
            HttpContext current = HttpContext.Current;
            if ((current.Items.Contains(DisposeModuleEnabled) && (bool)current.Items[DisposeModuleEnabled] == true) == false) throw new InvalidOperationException("(current.Items[\"DisposeModuleEnabled\"] == true) == false");
        }

        private void context_BeginRequest(object sender, EventArgs e)
        {
            HttpContext current = HttpContext.Current;

            current.Items[DisposeModuleEnabled] = true;
        }

        public static void AddDisposable(IDisposable disposable)
        {
            List<IDisposable> disposables = null;
            HttpContext current = HttpContext.Current;

            EnsureEnabled();

            disposables = (List<IDisposable>)current.Items[DisposeList];

            if (disposables == null)
            {
                disposables = new List<IDisposable>();
                current.Items[DisposeList] = disposables;
            }

            disposables.Add(disposable);
        }

        #endregion
    }
}
